package cn.format.b.format;

import java.io.PrintWriter;
import java.util.List;

import cn.format.b.error.SyntaxException;
import cn.format.b.format.MetaFormatter.Line;
import cn.format.b.lement.JsonElement;
import cn.format.b.lement.Token;

/**
 * @Copyright © 2017 sanbo Inc. All rights reserved.
 * @Description: update
 * @Version: 1.0
 * @Create: 2017年7月3日 下午4:06:27
 * @author: safei
 */
public class AJsonFormat implements JsonFormatter {
    private static final String TAB = "    ";

    private boolean withLineNo = false; // 是否输出行号
    private boolean withErrorInline = false; // 是否在行内输出错误指示
    private boolean withErrorDetail = false; // 是否输出详细错误信息

    public AJsonFormat() {
        this(false, false, false);
    }

    public AJsonFormat(boolean withLineNo, boolean withErrorInline, boolean withErrorDetail) {
        this.withLineNo = withLineNo;
        this.withErrorInline = withErrorInline;
        this.withErrorDetail = withErrorDetail;
    }

    public String format(JsonElement element) {
        final MetaFormatter format = new MetaFormatter();
        format.format(element);

        StringBuilder sb = new StringBuilder();
        final List<Line> lines = format.getLines();
        final List<SyntaxException> exceptions = format.getExceptions();

        final int lineNoWidth = getLineNoWidth(lines.size());
        int lineNo = 0;

        for (Line line : lines) {
            lineNo++;

            // 打印行号
            if (withLineNo) {
                if (lineNoWidth > 0) {
                    sb.append(String.format("%" + lineNoWidth + "d.", lineNo));
                } else {
                    sb.append(lineNo + ".");
                }
            }

            // 行内打印出错
            if (withErrorInline && !line.getExceptions().isEmpty()) {
                sb.append("=>");
            } else if (withLineNo || (withErrorInline && !exceptions.isEmpty())) {
                sb.append("  ");
            }

            // 打印前导空格
            for (int i = 0; i < line.getTabCount(); i++) {
                sb.append(TAB);
            }

            // 打印内容
            for (Token token : line.getTokens()) {
                final String s = token.getValue();
                if (token.getType() == Token.TYPE_KV_SEPARATOR) {
                    sb.append(" " + s + " ");
                } else {
                    sb.append(s);
                }
            }

            // may udpate
            sb.append("\n");
        }

        // 打印完整错误信息
        if (withErrorDetail && !exceptions.isEmpty()) {
            sb.append("\r\n");
            sb.append("==== syntax warnings & errors ====");
            for (SyntaxException e : exceptions) {
                sb.append(e.toString());
            }
        }
        return sb.toString();
    }

    @Override
    public void format(JsonElement element, PrintWriter pw) {
        final MetaFormatter format = new MetaFormatter();
        format.format(element, pw);

        final List<Line> lines = format.getLines();
        final List<SyntaxException> exceptions = format.getExceptions();

        final int lineNoWidth = getLineNoWidth(lines.size());
        int lineNo = 0;

        for (Line line : lines) {
            lineNo++;

            // 打印行号
            if (withLineNo) {
                if (lineNoWidth > 0) {
                    pw.print(String.format("%" + lineNoWidth + "d.", lineNo));
                } else {
                    pw.print(lineNo + ".");
                }
            }

            // 行内打印出错
            if (withErrorInline && !line.getExceptions().isEmpty()) {
                pw.print("=>");
            } else if (withLineNo || (withErrorInline && !exceptions.isEmpty())) {
                pw.print("  ");
            }

            // 打印前导空格
            for (int i = 0; i < line.getTabCount(); i++) {
                pw.print(TAB);
            }

            // 打印内容
            for (Token token : line.getTokens()) {
                final String s = token.getValue();
                if (token.getType() == Token.TYPE_KV_SEPARATOR) {
                    pw.print(" " + s + " ");
                } else {
                    pw.print(s);
                }
            }

            pw.println();
        }

        // 打印完整错误信息
        if (withErrorDetail && !exceptions.isEmpty()) {
            pw.println();
            pw.println("==== syntax warnings & errors ====");
            for (SyntaxException e : exceptions) {
                pw.println(e.toString());
            }
        }
    }

    private int getLineNoWidth(int totalLineNo) {
        int ret = 0;
        for (; totalLineNo > 0; totalLineNo /= 10) {
            ret++;
        }
        return ret;
    }

}
